﻿#pragma once

#include "Quat.h"

#include "Containers/String.h"

struct WHENGINE_API SMatrix3x3
{
	Float Data[3 /*Column*/][3 /*Row*/] = {};

	static SMatrix3x3 FromEuler(const SVec3& InRandian);

	//转换成欧拉角，单位为弧度
	SVec3 ToEuler() const;

	SMatrix3x3() {
		Data[0][0] = 1;
		Data[1][1] = 1;
		Data[2][2] = 1;
	};

	SMatrix3x3(const SVec3& Column0,const SVec3& Column1,const SVec3& Column2)
	{
		Data[0][0] = Column0.X;
		Data[0][1] = Column0.Y;
		Data[0][2] = Column0.Z;

		Data[1][0] = Column1.X;
		Data[1][1] = Column1.Y;
		Data[1][2] = Column1.Z;	

		Data[2][0] = Column2.X;
		Data[2][1] = Column2.Y;
		Data[2][2] = Column2.Z;		
	}

	SMatrix3x3(const SQuat& InQuat);

	static SMatrix3x3 Identity()
	{
		return SMatrix3x3();
	}

	static SMatrix3x3 Zero;

	SMatrix3x3 operator * (const SMatrix3x3& Right)
	{
		SMatrix3x3 Ret;
		for (int Row = 0; Row < 3; Row++)
		{
			for (int Column = 0; Column < 3; Column++)
			{
				Ret.Data[Column][Row] = Data[0][Row] * Right.Data[Column][0] 
									  + Data[1][Row] * Right.Data[Column][1]
					                   +Data[2][Row] * Right.Data[Column][2];
			}
		}

		return Ret;
	}

	SVec3 operator * (const SVec3& Point)
	{
		return SVec3(
				Data[0][0] * Point.X + Data[1][0] * Point.Y +Data[2][0] * Point.Z,
				Data[0][1] * Point.X + Data[1][1] * Point.Y +Data[2][1] * Point.Z,
				Data[0][2] * Point.X + Data[1][2] * Point.Y +Data[2][2] * Point.Z
		);
	}

	Float& At(int Column, int Row)
	{
		return Data[Column][Row];
	}

	SQuat ToQuat() const;

	CString ToString() const;

	//to array { C0R0,C0R1,C0R2,C1R0,C1R1..}
	void ToFloatArray(float OutArray[9]) const;

	//逆矩阵
	SMatrix3x3 Inverse() const;

	//转置矩阵
	SMatrix3x3 Transpose() const;
};

